extends Node3D

var sunbox: SunBox

class SunBox extends Node3D:
	# 所有sun都应该在这里
	var const_g: float = 6.674
	var suns: Array = []
	var mid: Vector3 = Vector3.ZERO
	
	func add_sun(mass: float, diam: float, loc: Vector3, vel: Vector3):
		var s: Sun = Sun.new(mass, diam, loc, vel)
		self.suns.append(s)
		self.add_child(s)
	
	func refresh_(dt: float):
		# 更新速度 位置 并更新动画
		for s in self.suns:
			if not s.inst:
				return
		var sum_v: Vector3
		var m_s: float
		var d_s: float
		var d_m: float
		var r: float
		var r_min: float
		var loc_s: Vector3
		var loc_m: Vector3
		# 更新速度
		for index_m in range(len(self.suns)):
			sum_v = Vector3.ZERO
			for index_s in range(len(self.suns)):
				if index_s == index_m:
					continue
				# a_m = g * m_s / (r) ** 2
				# v_m = a_m * dt
				m_s = self.suns[index_s].mass
				loc_s = self.suns[index_s].position
				loc_m = self.suns[index_m].position
				r = loc_s.distance_to(loc_m)
				d_s = self.suns[index_s].diameter
				d_m = self.suns[index_m].diameter
				r_min = (d_s + d_m) / 2
				r = max(r, r_min)
				sum_v += self.const_g * dt * m_s / (r ** 2) * ((loc_s - loc_m).normalized())
				self.suns[index_m].acc = sum_v / dt
			self.suns[index_m].vel += sum_v
		# 更新位置
		for sun in self.suns:
			sun.position += sun.vel * dt

	func refresh_mid() -> Vector3:
		# 设置相机原点为所有星球的几何中心
		var p: Vector3 = Vector3.ZERO
		for s in self.suns:
			p += s.position
		p /= len(self.suns)
		self.mid = p
		return p
	
	func del_suns():
		for s in self.suns:
			s.get_parent().remove_child(s)
			s.queue_free()
		self.suns = []

class Sun extends Node3D:
	var diameter: float = 1.
	var mass: float = 1.
	var inst: Node3D
	var vel: Vector3
	var acc: Vector3
	
	func _init(mass: float, diam: float, loc: Vector3, vel: Vector3):
		self.mass = mass
		self.diameter = diam
		self.position = loc
		self.vel = vel

	func _ready() -> void:
		self.inst = load("res://scene/sun.tscn").instantiate()
		self.inst.scale = Vector3(self.diameter, self.diameter, self.diameter)
		self.add_child(self.inst)
	
	func on_del() -> void:
		# 删除实例
		self.inst.get_parent().remove_child(self.inst)
		self.inst.queue_free()
		self.inst = null

func _ready() -> void:
	Global.log.info("启动")
	Global.log.info("开始读取配置文件")
	Global._get_user_profile()
	Global.log.info("应用全局配置参数")
	sunbox = SunBox.new()
	sunbox.const_g = Global.global_config.const_g
	Global.log.info("锁定fps: %d"%Global.global_config.fps)
	Engine.max_fps = Global.global_config.fps
	Global.log.info("生成星球1")
	Global.log.info("质量: %f"%Global.sun_1_config.mass)
	Global.log.info("显示直径: %f"%Global.sun_1_config.diam)
	Global.log.info("初始位置: X=%f Y=%f Z=%f"% \
		[Global.sun_1_config.loc.x, Global.sun_1_config.loc.y, Global.sun_1_config.loc.z])
	Global.log.info("初始速度: X=%f Y=%f Z=%f"% \
		[Global.sun_1_config.vel.x, Global.sun_1_config.vel.y, Global.sun_1_config.vel.z])
	sunbox.add_sun(
		Global.sun_1_config.mass, 
		Global.sun_1_config.diam, 
		Global.sun_1_config.loc, Global.sun_1_config.vel)
		
	Global.log.info("生成星球2")
	Global.log.info("质量: %f"%Global.sun_2_config.mass)
	Global.log.info("显示直径: %f"%Global.sun_2_config.diam)
	Global.log.info("初始位置: X=%f Y=%f Z=%f"% \
		[Global.sun_2_config.loc.x, Global.sun_2_config.loc.y, Global.sun_2_config.loc.z])
	Global.log.info("初始速度: X=%f Y=%f Z=%f"% \
		[Global.sun_2_config.vel.x, Global.sun_2_config.vel.y, Global.sun_2_config.vel.z])
	sunbox.add_sun(
		Global.sun_2_config.mass, 
		Global.sun_2_config.diam, 
		Global.sun_2_config.loc, Global.sun_2_config.vel)
	
	Global.log.info("生成星球3")
	Global.log.info("质量: %f"%Global.sun_3_config.mass)
	Global.log.info("显示直径: %f"%Global.sun_3_config.diam)
	Global.log.info("初始位置: X=%f Y=%f Z=%f"% \
		[Global.sun_3_config.loc.x, Global.sun_3_config.loc.y, Global.sun_3_config.loc.z])
	Global.log.info("初始速度: X=%f Y=%f Z=%f"% \
		[Global.sun_3_config.vel.x, Global.sun_3_config.vel.y, Global.sun_3_config.vel.z])
	sunbox.add_sun(
		Global.sun_3_config.mass, 
		Global.sun_3_config.diam, 
		Global.sun_3_config.loc, Global.sun_3_config.vel)
	
	add_child(sunbox)
	Global.sunbox = sunbox

func _physics_process(delta: float) -> void:
	sunbox.refresh_(delta)

func _input(event: InputEvent) -> void:
	var camera: Camera3D = $Camera3D
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
			var now_dist: Vector3 = camera.position
			var target: Vector3 = sunbox.refresh_mid()
			camera.position = (camera.position - target) * 1.1 + target
		elif event.button_index == MOUSE_BUTTON_WHEEL_UP:
			var now_dist: Vector3 = camera.position
			var target: Vector3 = sunbox.refresh_mid()
			var lm: Vector3 = (camera.position - target) / 1.1
			var l: float = lm.length()
			lm = lm.normalized()
			l = max(l, 15)
			lm *= l
			camera.position = lm + target
		elif event.button_index == MOUSE_BUTTON_LEFT:
			Global.rotate_btn = event.pressed
	elif event is InputEventMouseMotion:
		if Global.rotate_btn:
			var target: Vector3 = sunbox.refresh_mid()
			# 反解相机角度
			var vec: Vector3 = camera.position - target
			var dist: float = vec.length()
			var pitch: float = asin(vec.y / dist)
			var yaw: float = atan2(vec.x, vec.z)
			# 更新角度
			yaw -= event.relative.x * Global.sensitive
			pitch += event.relative.y * Global.sensitive
			pitch = clamp(pitch, -PI/2 + 0.1, PI/2 - 0.1) # 防止翻转
			# 重新设置相机
			var x = target.x + dist * sin(yaw) * cos(pitch)
			var y = target.y + dist * sin(pitch)
			var z = target.z + dist * cos(yaw) * cos(pitch)
			camera.position = Vector3(x, y, z)
			camera.look_at(target, Vector3.UP)
	elif event is InputEventKey and event.pressed:
		if event.keycode == KEY_ESCAPE:
			if not Global.menu_box:
				Global.menu_box = Global.menu_box_res.instantiate()
				add_child(Global.menu_box)
			else:
				Global.menu_box.get_parent().remove_child(Global.menu_box)
				Global.menu_box.queue_free()
				Global.menu_box = null
			
